package org.web.webdisplay.server.biz.impl;

import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.lang3.StringUtils;
import org.web.base.domain.ResultDO;
import org.web.webdisplay.sdk.dto.DisplayInfoDTO;
import org.web.webdisplay.sdk.dto.query.QueryDisplayInfoRequest;
import org.web.webdisplay.server.service.DisplayInfoService;

import java.util.*;

import org.springframework.stereotype.Service;


import jakarta.annotation.Resource;

import org.apache.log4j.Logger;
import org.web.webdisplay.sdk.biz.DisplayInfoBiz;
import org.web.webdisplay.server.domain.query.QueryDisplayInfo;
import org.web.webdisplay.server.domain.DisplayInfoDO;
import org.web.base.domain.exception.ResultMessageEnum;
import org.web.base.domain.helper.*;

import java.util.List;
import java.util.stream.Collectors;

@Service("DisplayInfoBiz")
public class DisplayInfoBizImpl implements DisplayInfoBiz {

    private final Logger logger = Logger.getLogger(DisplayInfoBizImpl.class);

    @Resource
    private DisplayInfoService displayInfoService;

    @Override
    public ResultDO<List<DisplayInfoDTO>> selectDisplayInfoList(QueryDisplayInfoRequest queryDisplayInfoRequest) {
        ResultDO<List<DisplayInfoDTO>> resultDO = new ResultDO<>();
        try {
            if (queryDisplayInfoRequest == null) {
                throw ServiceExceptionHelper.buildServiceException(ResultMessageEnum.PARAM_EMPTY);
            }
            queryDisplayInfoRequest.checkAndBuildQuery();
            ValidationHelper.validateWithThrow(QueryDisplayInfoRequest.class, queryDisplayInfoRequest);
            QueryDisplayInfo queryDisplayInfo = new QueryDisplayInfo();
            BeanUtils.copyProperties(queryDisplayInfo, queryDisplayInfoRequest);
            List<DisplayInfoDO> selectList = displayInfoService.selectDisplayInfoList(queryDisplayInfo);
            List<DisplayInfoDTO> list = new ArrayList<>();
            resultDO.setDomain(list);
            for (DisplayInfoDO displayInfoDO : selectList) {
                DisplayInfoDTO displayInfoDTO = new DisplayInfoDTO();
                BeanUtils.copyProperties(displayInfoDTO, displayInfoDO);
                list.add(displayInfoDTO);
            }
        } catch (Exception e) {
            logger.error(ServiceExceptionHelper.getExceptionInfo(e));
            return ResultHelper.buildResultDOByException(e);
        }
        return resultDO;
    }

    @Override
    public ResultDO<Integer> countDisplayInfoList(QueryDisplayInfoRequest queryDisplayInfoRequest) {
        ResultDO<Integer> resultDO = new ResultDO<>();
        try {
            if (queryDisplayInfoRequest == null) {
                throw ServiceExceptionHelper.buildServiceException(ResultMessageEnum.PARAM_EMPTY);
            }
            ValidationHelper.validateWithThrow(QueryDisplayInfoRequest.class, queryDisplayInfoRequest);
            QueryDisplayInfo queryDisplayInfo = new QueryDisplayInfo();
            BeanUtils.copyProperties(queryDisplayInfo, queryDisplayInfoRequest);
            Integer count = displayInfoService.countDisplayInfoList(queryDisplayInfo);
            resultDO.setDomain(count);
        } catch (Exception e) {
            logger.error(ServiceExceptionHelper.getExceptionInfo(e));
            return ResultHelper.buildResultDOByException(e);
        }
        return resultDO;
    }

    /***
     * 1、参数校验
     *
     */
    @Override
    public ResultDO<List<DisplayInfoDTO>> batchSaveDisplayInfoList(List<DisplayInfoDTO> list) {
        ResultDO<List<DisplayInfoDTO>> resultDO = new ResultDO<>();
        try {
            //1、分拆数组，并初始化默认值
            ListSplitResult splitList = ListHelper.splitList(list, DisplayInfoDTO::getDisplayInfoId);
            List<DisplayInfoDTO> insertDTOList = splitList.getInsertList();
            List<DisplayInfoDTO> updateDTOList = splitList.getUpdateList();

            for (DisplayInfoDTO needInsert : insertDTOList) {
                if (StringUtils.isEmpty(needInsert.getAppName())) {
                    needInsert.setAppName("DEFAULT");
                }
                if (StringUtils.isEmpty(needInsert.getIntlLanguage())) {
                    needInsert.setIntlLanguage("zh");
                }
            }

            //2、参数校验
            ListHelper.checkListDataValidate(splitList);

            //3、为updateDTOList, 补全唯一性属性信息。
            Set<Integer> updateIdSet = updateDTOList.stream()
                    .map(DisplayInfoDTO::getDisplayInfoId)
                    .collect(Collectors.toSet());

            if(!updateIdSet.isEmpty()){
                QueryDisplayInfo filterUpdateQuery = new QueryDisplayInfo();
                filterUpdateQuery.setDisplayInfoIdSet(updateIdSet);
                filterUpdateQuery.setSpecifiedAttributeSet(new HashSet<>(Arrays.asList("display_info_id", "app_name", "intl_language", "page_name","display_info")));
                Map<Integer, DisplayInfoDO> selectDisplayInfoListByUpdateList = displayInfoService.selectDisplayInfoMapForDisplayInfoId(filterUpdateQuery);
                if (selectDisplayInfoListByUpdateList.size() < updateIdSet.size()) {
                    Set<Integer> updateIdSetFromDB = selectDisplayInfoListByUpdateList.values().stream()
                            .map(DisplayInfoDO::getDisplayInfoId)
                            .collect(Collectors.toSet());
                    Set<Integer> missSet = SetHelper.getSymmetricDifference(updateIdSetFromDB, updateIdSet);
                    String result = missSet.stream()
                            .map(String::valueOf)
                            .collect(Collectors.joining(","));
                    throw ServiceExceptionHelper.buildServiceException(ResultMessageEnum.DATA_NOT_EXIST, "主键在数据库中未找到,缺少的主键信息为" + result);
                } else {
                    List<DisplayInfoDTO> changedUniqueList = new ArrayList<>();
                    for (DisplayInfoDTO displayInfoDTO : updateDTOList) {
                        DisplayInfoDO displayInfoDO = selectDisplayInfoListByUpdateList.get(displayInfoDTO.getDisplayInfoId());
                        displayInfoDTO.setDisplayInfoPreVersion(displayInfoDO.getDisplayInfo());// 不能放到后面
                        boolean changeUniqueFlag = false;
                        if (StringUtils.isEmpty(displayInfoDTO.getAppName())) {
                            displayInfoDTO.setAppName(displayInfoDO.getAppName());
                        } else if (!displayInfoDTO.getAppName().equals(displayInfoDO.getAppName())) {
                            // 不同，说明改变了唯一性
                            changeUniqueFlag = true;
                        }
                        if (StringUtils.isEmpty(displayInfoDTO.getIntlLanguage())) {
                            displayInfoDTO.setIntlLanguage(displayInfoDO.getIntlLanguage());
                        } else if (!displayInfoDTO.getIntlLanguage().equals(displayInfoDO.getIntlLanguage())) {
                            // 不同，说明改变了唯一性
                            changeUniqueFlag = true;
                        }
                        if (StringUtils.isEmpty(displayInfoDTO.getPageName())) {
                            displayInfoDTO.setAppName(displayInfoDO.getPageName());
                        } else if (!displayInfoDTO.getPageName().equals(displayInfoDO.getPageName())) {
                            // 不同，说明改变了唯一性
                            changeUniqueFlag = true;
                        }

                        if (changeUniqueFlag) {
                            changedUniqueList.add(displayInfoDTO);
                        }
                    }

                    if (!changedUniqueList.isEmpty()) {
                        QueryDisplayInfo checkLogicUniqueQuery = new QueryDisplayInfo();
                        for (DisplayInfoDTO needUpdate : changedUniqueList) {
                            checkLogicUniqueQuery.setAppName(needUpdate.getAppName());
                            checkLogicUniqueQuery.setIntlLanguage(needUpdate.getIntlLanguage());
                            checkLogicUniqueQuery.setPageName(needUpdate.getPageName());
                            DisplayInfoDO fromDB = displayInfoService.selectOneDisplayInfo(checkLogicUniqueQuery);
                            if (fromDB != null) {
                                throw ServiceExceptionHelper.buildServiceException(ResultMessageEnum.DATA_NOT_EXIST, "待修改的数据信息，导致数据唯一性冲突。" + needUpdate.toString());
                            }
                        }
                    }
                }
            }
            ListHelper.checkBatchListDuplication(list);

            // 数据库校验新增的数据，根据逻辑唯一性，判断数据是否存，如果存在，则放置到updateDTOList中。
            List<DisplayInfoDTO> filterInsertList = new ArrayList<>();
            QueryDisplayInfo checkLogicUniqueQuery = new QueryDisplayInfo();
            checkLogicUniqueQuery.setSpecifiedAttributeSet(new HashSet<>(Arrays.asList("display_info_id")));
            for (DisplayInfoDTO needInsert : insertDTOList) {
                checkLogicUniqueQuery.setAppName(needInsert.getAppName());
                checkLogicUniqueQuery.setPageName(needInsert.getPageName());
                checkLogicUniqueQuery.setIntlLanguage(needInsert.getIntlLanguage());
                DisplayInfoDO fromDB = displayInfoService.selectOneDisplayInfo(checkLogicUniqueQuery);
                if (fromDB != null) {
                    needInsert.setDisplayInfo(fromDB.getDisplayInfo());
                    updateDTOList.add(needInsert);
                } else {
                    needInsert.setDisplayInfoPreVersion("DEFAULT");
                    filterInsertList.add(needInsert);
                }
            }

            List<DisplayInfoDO> insertList = new ArrayList<>();
            List<DisplayInfoDO> updateList = new ArrayList<>();
            Map<String, DisplayInfoDO> insertDTOMap = new HashMap<>();
            for (DisplayInfoDTO displayInfoDTO : filterInsertList) {
                DisplayInfoDO displayInfoDO = new DisplayInfoDO();
                BeanUtils.copyProperties(displayInfoDO, displayInfoDTO);
                insertList.add(displayInfoDO);
                insertDTOMap.put(displayInfoDTO.toString(), displayInfoDO);
            }
            for (DisplayInfoDTO displayInfoDTO : updateDTOList) {
                DisplayInfoDO displayInfoDO = new DisplayInfoDO();
                BeanUtils.copyProperties(displayInfoDO, displayInfoDTO);
                updateList.add(displayInfoDO);
            }
            if (!insertList.isEmpty()) {
                displayInfoService.batchInsertDisplayInfoList(insertList);
            }
            if (!updateList.isEmpty()) {
                displayInfoService.batchUpdateDisplayInfoList(updateList);
            }
            for (DisplayInfoDO insertDisplayInfoDO : insertList) {
                insertDTOMap.get(insertDisplayInfoDO.toString()).setDisplayInfoId(insertDisplayInfoDO.getDisplayInfoId());
            }
            List<DisplayInfoDTO> afterBatchList = new ArrayList<>();
            resultDO.setDomain(afterBatchList);
            afterBatchList.addAll(filterInsertList);
            afterBatchList.addAll(updateDTOList);
        } catch (Exception e) {
            return ResultHelper.buildResultDOByException(e);
        }
        return resultDO;
    }



    @Override
    public ResultDO<Integer> batchDeleteDisplayInfoList(List<Integer> displayInfoIdList) {
        ResultDO<Integer> resultDO = new ResultDO<>();
        List<DisplayInfoDO> list = new ArrayList<>();
        for (Integer primaryKey : displayInfoIdList) {
            DisplayInfoDO displayInfoDO = new DisplayInfoDO();
            displayInfoDO.setDisplayInfoId(primaryKey);
            displayInfoDO.setIsDelete("Y");
            list.add(displayInfoDO);
        }
        int number = displayInfoService.batchUpdateDisplayInfoList(list).size();
        resultDO.setDomain(number);
        return resultDO;
    }
}
